#pragma once

#include <thread>

#include "VideoStateEnum.cpp"

extern "C" {
#include <jni.h>
#include <log/log.h>
}

jobject gPListener{nullptr};
jobject gPSurface{nullptr};
JavaVM *gPVm{nullptr};

/**
 * 附加到当前Jvm线程
 */
class JniEnv {
public:
    JniEnv() {
        if (gPVm == nullptr) {
            throw "JVM已经被销毁";
        }
        int getEnvStat = gPVm->GetEnv((void **) &env, JNI_VERSION_1_6);
        if (getEnvStat == JNI_EDETACHED) {
            needDetach = true;
            if (gPVm->AttachCurrentThread(&env, nullptr) != 0) {
                throw "附加到线程失败";
            }
        }
    }

    ~JniEnv() {
        if (needDetach) {
            gPVm->DetachCurrentThread();
        }
    }

    JNIEnv *operator->() { return env; }

    JNIEnv *operator*() { return env; }

    JniEnv(const JniEnv &) = delete;

    JniEnv &operator=(const JniEnv &) = delete;

    JniEnv(const JniEnv &&) = delete;

    JniEnv &operator=(const JniEnv &&) = delete;


private:
    JNIEnv *env;
    bool needDetach{false};
};

std::mutex replayStatusMutex;

void replayPlayStatus(VideoStateEnum videoStateEnum) {
    std::lock_guard<std::mutex> lock{replayStatusMutex};
    if (gPListener == nullptr) {
        LOGE("no found callback listener");
        return;
    }
    JniEnv attach;
    //获取到要回调的类
    jclass javaClass = attach->GetObjectClass(gPListener);
    if (javaClass == 0) {
        LOGE("no found callback class");
        return;
    }
    //获取要回调的方法ID
    jmethodID javaCallbackId = attach->GetMethodID(javaClass, "onChange", "(I)V");
    if (javaCallbackId == nullptr) {
        LOGE("no found callback method");
        return;
    }
    attach->CallVoidMethod(gPListener, javaCallbackId, videoStateEnum);
    attach->DeleteLocalRef(javaClass);
}

void releaseGlobal(JNIEnv *env) {
    if (gPSurface != nullptr) {
        env->DeleteGlobalRef(gPSurface);
        gPSurface = nullptr;
    }
    if (gPListener != nullptr) {
        std::lock_guard<std::mutex> lock{replayStatusMutex};
        env->DeleteGlobalRef(gPListener);
        gPListener = nullptr;
    }
}

auto getCharFormJava(JNIEnv *env, jstring string) {
    const char *stringRaw = env->GetStringUTFChars(string, nullptr);
    auto cString = std::shared_ptr<char>(new char[strlen(stringRaw) + 1], [](auto c) {
        delete[] c;
    });
    std::strcpy(cString.get(), stringRaw);
    env->ReleaseStringUTFChars(string, stringRaw);
    return cString;
}